package com.example.servicetest

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewConfiguration
import android.view.animation.DecelerateInterpolator
import android.view.animation.LinearInterpolator
import android.widget.Scroller
import androidx.appcompat.widget.LinearLayoutCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.toRectF
import com.example.servicetest.util.MyViscousFluidInterpolator
import java.lang.reflect.Field
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToInt

class TextPixelsCanvas : View {


    /**
     * 一排有多少个像素点
     */
    private var mBoxRowCount = 44

    /**
     * 一排最少有多少个像素点
     */
    private val mMinBoxRowCount = 44

    /**
     * 一列有多少个像素点
     */
    private val mBoxColumnCount = 16

    /**
     * 间隔
     */
    private val mBoxGap: Float = 3f

    /**
     * 单个格子宽度
     */
    private var mBoxWith: Float = 0f

    /**
     * 单个格子高度
     */
    private var mBoxHeight: Float = 0f

    /**
     * 背景颜色的二维数组
     */
    private var mBgColorArray = mutableListOf<MutableList<Int>>()

    /**
     * 文字图片的二位数组
     */
    private val mTextColorArray = mutableListOf<MutableList<Int>>()

    /**
     * 负责平缓滑动,先加速后减速
     */
    private val mScroller: Scroller by lazy { Scroller(context,DecelerateInterpolator()) }

    /**
     * 获取系统移动阀值,移动距离超出该数值则为移动
     */
    private val mTouchSlop: Int by lazy { ViewConfiguration.get(context).scaledTouchSlop }

    /**
     * x轴的最小速率,这是原生的一个参考值,小于这个值可以认为是无滑动惯性
     */
    private val mMinVelocity: Int by lazy { ViewConfiguration.get(context).scaledMinimumFlingVelocity }

    /**
     * 表示目前处于fling的滑动中.
     */
    private var isFling = false

    /**
     * 说明现在的操作是手指抬起之后.
     */
    private var mPressUp = false

    /**
     * 判断是否移动过
     */
    private var mTouchMove: Boolean = false

    /**
     * 移动中
     */
    private var mMoving: Boolean = false

    /**
     * 上一次的触摸点x坐标
     */
    private var mPreX: Float = 0.0f

    /**
     * 格子的画笔
     */
    private var mBoxPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)

    /**
     * 统一格子颜色
     */
    private var mBoxesColor: Int

    /**
     * 用于背景图片等比缩放后的大小
     */
    private var mBoxRect: Rect = Rect()

    /**
     * 绘制文字前景色的区域
     */
    private var mTextForegroundRect: Rect = Rect()

    /**
     * 裁剪区域,避免绘制屏幕外面的区域,用于提高性能
     */
    private var mClipRect: Rect = Rect()

    /**
     * 文字前景色的颜色
     */
    private var mTextForegroundPaint: Paint = Paint()

    /**
     * 清楚画布的画布
     */
    private var mClearPaint: Paint = Paint()

    /**
     * VelocityTracker是android提供的用来记录滑动速度的一个类，可以监控手指移动的速度
     */
    private val mVelocityTracker: VelocityTracker by lazy { VelocityTracker.obtain(); }

    /**
     * 存储单个字符的横向像素长度,用于文本删除
     */
    private val mCharBitmapWithList = mutableListOf<Int>()

    /**
     * 背景颜色线性颜色的保存
     */
    private var mLinearGradientColorArray: IntArray? = null

    /**
     * 背景颜色线性颜色的方向
     * -1纯色、0水平、1垂直
     */
    private var mOrientation: Int = -1

    /**
     * 也就是过滤一下 不会那么频繁的去调用而已.
     */
    private val mPreDistance = -1f

    /**
     * 0.常态 1.左移 2 右移 3 闪烁
     */
    var mTurnMode =  NORMALIZATION_MODE

    /**
     * 在 mTurnMode = 3 下true为显示,false为隐藏
     */
    var mIsFlashing =  false

    /**
     * 0-100, 移动或者闪烁速度,禁止直接使用速度,需要通过getScrollSpeed()使用速度,避免不同分辨率的手机滑动速度不一致
     */
    private var mSpeed = 50

    private var mViewHandler:ViewHandler? = ViewHandler(Looper.getMainLooper())

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        setLayerType(LAYER_TYPE_SOFTWARE,null)

        mBoxesColor = ContextCompat.getColor(context, android.R.color.black)

        mTextForegroundPaint.color = Color.WHITE
        mTextForegroundPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)

        mClearPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)

        for (columnIndex in 0 until mBoxColumnCount) {
            val rowColorArray = mutableListOf<Int>()
            for (rowIndex in 0 until mBoxRowCount) {
                rowColorArray.add(mBoxesColor)
            }
            mBgColorArray.add(rowColorArray)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val withSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)

        val newHeightMeasureSpec = when (heightMode) {
            MeasureSpec.EXACTLY,
            MeasureSpec.AT_MOST -> {
                //计算单个格子的宽高
                mBoxWith = ((withSize - (mBoxGap * (mMinBoxRowCount - 1) - paddingStart - paddingEnd)) / mMinBoxRowCount).toFloat()

                mBoxHeight = mBoxWith

                //测量高度
                var height: Int = (mBoxHeight * mBoxColumnCount + paddingTop + paddingBottom + mBoxGap * (mBoxColumnCount - 1)).toInt()
                //如超父类高度重新测量
                if (height > heightSize) {
                    height = heightSize
                    //重新计算单个盒子高度
                    mBoxHeight = max(0f, (heightSize - mBoxGap * (mBoxColumnCount - 1) - paddingBottom - paddingTop) / mBoxColumnCount)
                }
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
            }
            else -> {
                //计算单个格子的宽高
                mBoxWith = (withSize - (mBoxGap * (mMinBoxRowCount - 1) + paddingStart + paddingEnd)) / mMinBoxRowCount
                mBoxHeight = mBoxWith

                //测量高度
                val height: Int = (mBoxHeight * mBoxColumnCount + paddingTop + paddingBottom + mBoxGap * (mBoxColumnCount - 1)).toInt()
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
            }
        }
        super.onMeasure(widthMeasureSpec, newHeightMeasureSpec)
    }

    override fun computeScroll() {
        //判断是否滚动完成,true说明滚动尚未完成，false说明滚动已经完成
        if (mScroller.computeScrollOffset()) {
            if (mScroller.currX == mScroller.finalX && mPressUp && isFling) {
                mPressUp = false
                isFling = false
                scrollFinish()
            }
            scrollTo(mScroller.currX, 0)
            postInvalidate()
        }
        super.computeScroll()
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                mPressUp = false
                isFling = false
                mTouchMove = false
                mMoving = false
                mPreX = event.x
                if(isEnableSlide()){
                    mVelocityTracker.clear()
                    mVelocityTracker.addMovement(event);
                    mScroller.forceFinished(true)
                }
            }
            MotionEvent.ACTION_MOVE -> {
                if (abs(event.x - mPreX) > mTouchSlop &&!mTouchMove) {
                    mTouchMove = true
                    if(isEnableSlide()){
                        mVelocityTracker.addMovement(event)
                        val distance: Float = event.x - mPreX
                        if (mPreDistance != distance) {
                            doScroll(-distance.toInt())
                            invalidate()
                        }
                    }
                    mPreX = event.x
                }else{
                    if(mTouchMove){
                        if(isEnableSlide()){
                            mVelocityTracker.addMovement(event)
                            val distance: Float = event.x - mPreX
                            if (mPreDistance != distance) {
                                doScroll(-distance.toInt())
                                invalidate()
                            }
                        }
                        mPreX = event.x
                    }
                }
            }
            MotionEvent.ACTION_UP -> {
                mPressUp = true
                if (mTouchMove) {
                    mVelocityTracker.computeCurrentVelocity(500)
                    val xVelocity: Float = mVelocityTracker.xVelocity
                    if (abs(xVelocity) >= mMinVelocity) {
                        if(isEnableSlide()){
                            isFling = true
                            val centerPointX: Int = width/10
                            val velocityX = (xVelocity * 0.35).toInt()
                            mScroller.fling(
                                mScroller.currX,
                                0,
                                -velocityX,
                                0,
                                -centerPointX,
                                calculateHorizontalWith()-width+centerPointX,
                                0,
                                0
                            )
                            invalidate()
                        }
                    } else {
                        isFling = false
                        if(isEnableSlide()){
                            scrollFinish()
                        }
                    }
                } else {
                    performClick()
                }
                mVelocityTracker.clear()
            }

        }
        return true
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    private fun doScroll(dx: Int) {
        Log.i("doScroll", "doScroll: ${mScroller.finalX}")
        mScroller.startScroll(mScroller.finalX, mScroller.finalY, dx, 0, 0)
    }

    /**
     * 滑动停止之后重新定位,处理越界回弹
     */
    private fun scrollFinish() {
        val finalX = mScroller.finalX
        if(finalX<width/10){
            mScroller.startScroll(
                mScroller.finalX,
                mScroller.finalY,
                -mScroller.finalX,
                0,
                300)
        }else {
            if(calculateHorizontalWith()>width){
                if(mScroller.finalX>calculateHorizontalWith()-width){
                    mScroller.startScroll(
                        mScroller.finalX,
                        mScroller.finalY,
                        -((width-paddingStart-paddingEnd)-(calculateHorizontalWith()-mScroller.finalX)),
                        0,
                        300)
                }
            }else{
                mScroller.startScroll(
                    mScroller.finalX,
                    mScroller.finalY,
                    -mScroller.finalX,
                    0,
                    300)
            }
        }
        invalidate()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        mClipRect.run {
            left = paddingLeft + mScroller.currX
            top = paddingTop
            right = this@TextPixelsCanvas.width - paddingEnd +mScroller.currX
            bottom = this@TextPixelsCanvas.height - paddingBottom
        }
        canvas.clipRect(mClipRect)

        drawCell(canvas)
        if(mTurnMode == FLASH_MODE){
            if(mIsFlashing){
                val layerId = canvas.saveLayer(mTextForegroundRect.toRectF(), null)
                drawText(canvas)
                drawTextForegroundColor(canvas)
                canvas.restoreToCount(layerId)
            }
        }else{
            val layerId = canvas.saveLayer(mTextForegroundRect.toRectF(), null)
            drawText(canvas)
            drawTextForegroundColor(canvas)
            canvas.restoreToCount(layerId)
        }

        canvas.restore()
    }

    private fun drawTextForegroundColor(canvas: Canvas) {
        mTextForegroundRect.run {
            left = paddingLeft+mScroller.currX
            top = paddingTop
            right = this@TextPixelsCanvas.width - paddingRight+mScroller.currX
            bottom = this@TextPixelsCanvas.height - paddingBottom
        }
        Log.i("TAG","LEFT = ${mTextForegroundRect.left},TOP = ${mTextForegroundRect.top},RIGHT = ${mTextForegroundRect.right},BOTTOM = ${mTextForegroundRect.bottom},with = ${mTextForegroundRect.right - mTextForegroundRect.left}")
        canvas.drawRect(mTextForegroundRect,mTextForegroundPaint)
    }

    /**
     * 设置文字颜色,纯色设置
     */
    fun setTextColor(color: Int){
        if(color != mTextForegroundPaint.color || mTextForegroundPaint.shader != null){
            mTextForegroundPaint.color = color
            mTextForegroundPaint.shader = null
            invalidate()
        }
    }

    /**
     * 设置文字颜色,纯色设置
     */
    fun setTextLinearGradientColors(
        colors: IntArray,
        @LinearLayoutCompat.OrientationMode orientation: Int = LinearLayoutCompat.VERTICAL,
    ){
        mTextForegroundPaint.shader = LinearGradient(
            0f,
            0f,
            if(orientation == LinearLayoutCompat.VERTICAL) 0f else width.toFloat(),
            if(orientation == LinearLayoutCompat.VERTICAL) height.toFloat() else 0f,
            MyTextUtils.getColorFromRes(colors),
            null,
            Shader.TileMode.REPEAT
        )
        invalidate()
    }

    /**
     * 绘制文字
     */
    private fun drawText(canvas: Canvas) {
        for (columnIndex in 0 until mTextColorArray.size) {
            for (rowIndex in 0 until mTextColorArray[columnIndex].size) {
                mBoxRect.set(
                    (paddingStart.toFloat() + mBoxWith * rowIndex + mBoxGap * rowIndex).roundToInt(),
                    (paddingTop.toFloat() + mBoxHeight * columnIndex + mBoxGap * columnIndex).roundToInt(),
                    (paddingStart.toFloat() + mBoxWith * (rowIndex + 1) + mBoxGap * rowIndex).roundToInt(),
                    (paddingTop.toFloat() + mBoxHeight * (columnIndex + 1) + mBoxGap * columnIndex).roundToInt(),
                )
                mBoxPaint.color = mTextColorArray[columnIndex][rowIndex]
                canvas.drawRect(mBoxRect, mBoxPaint)
            }
        }

    }

    /**
     * 画方格
     */
    @SuppressLint("WrongConstant")
    private fun drawCell(canvas: Canvas) {
        mBoxPaint.run {
            isAntiAlias = true
            style = Paint.Style.FILL
            color = mBoxesColor
        }
        for (columnIndex in 0 until mBoxColumnCount) {
            for (rowIndex in 0 until mBoxRowCount) {
                mBoxRect.set(
                    (paddingStart.toFloat() + mBoxWith * rowIndex + mBoxGap * rowIndex).roundToInt(),
                    (paddingTop.toFloat() + mBoxHeight * columnIndex + mBoxGap * columnIndex).roundToInt(),
                    (paddingStart.toFloat() + mBoxWith * (rowIndex + 1) + mBoxGap * rowIndex).roundToInt(),
                    (paddingTop.toFloat() + mBoxHeight * (columnIndex + 1) + mBoxGap * columnIndex).roundToInt(),
                )
                mBoxPaint.color = mBgColorArray[columnIndex][rowIndex]
                canvas.drawRect(mBoxRect, mBoxPaint)
                mBoxRect.setEmpty()
            }
        }

        if(mTurnMode == RIGHT_MODE || mTurnMode == LEFT_MODE){

            var colorsRight:MutableList<MutableList<Int>> = mutableListOf()
            var colorsLeft:MutableList<MutableList<Int>> = mutableListOf()

            if(mOrientation == LinearLayoutCompat.HORIZONTAL){
                val bgBitmap = MyTextUtils.getBgBitmap(
                    colors = intArrayOf(mBgColorArray.last().last(),mBgColorArray.first().first()),
                    orientation = mOrientation,
                    width = mMinBoxRowCount
                )
                colorsRight = MyTextUtils.getColorArray(bgBitmap)

                val bgBitmap1 = MyTextUtils.getBgBitmap(
                    colors = intArrayOf(mBgColorArray.first().first(),mBgColorArray.last().last()),
                    orientation = mOrientation,
                    width = mMinBoxRowCount
                )
                colorsLeft = MyTextUtils.getColorArray(bgBitmap1)
            }


            if(mScroller.currX< 0+20 && mScroller.currX> -width-20){
                for (columnIndex in 0 until mBoxColumnCount) {
                    for (rowIndex in 0 until mMinBoxRowCount) {

                        mBoxRect.set(
                            (paddingEnd - mBoxGap*(rowIndex+1) - mBoxWith*(rowIndex+1)).toInt(),
                            (paddingTop.toFloat() + mBoxHeight * columnIndex + mBoxGap * columnIndex).toInt(),
                            (paddingEnd - mBoxGap*(rowIndex+1) - mBoxWith*rowIndex).toInt(),
                            (paddingTop + mBoxHeight * (columnIndex + 1) + mBoxGap * columnIndex).toInt(),
                        )
                        mBoxPaint.color = if(mOrientation == LinearLayoutCompat.HORIZONTAL){
                            colorsLeft[columnIndex][rowIndex]
                        }else{
                            mBgColorArray[0][rowIndex]
                        }
                        canvas.drawRect(mBoxRect, mBoxPaint)
                        mBoxRect.setEmpty()

                    }
                }
            }
            if(-mScroller.currX<= calculateHorizontalWith()+20 && mScroller.currX>= 0-20){
                for (columnIndex in 0 until mBoxColumnCount) {
                    for (rowIndex in 0 until mMinBoxRowCount) {
                        mBoxRect.set(
                            (paddingStart+calculateHorizontalWith() + mBoxGap*(rowIndex+1) + mBoxWith*rowIndex).toInt(),
                            (paddingTop.toFloat() + mBoxHeight * columnIndex + mBoxGap * columnIndex).toInt(),
                            (paddingStart+calculateHorizontalWith() +  mBoxGap*(rowIndex+1) + mBoxWith*(rowIndex+1)).toInt(),
                            (paddingTop + mBoxHeight * (columnIndex + 1) + mBoxGap * columnIndex).toInt(),
                        )
                        mBoxPaint.color = if(mOrientation == LinearLayoutCompat.HORIZONTAL){
                            colorsRight[columnIndex][rowIndex]
                        }else{
                            mBgColorArray[0][rowIndex]
                        }
                        canvas.drawRect(mBoxRect, mBoxPaint)
                        mBoxRect.setEmpty()

                    }
                }
            }
        }

    }

    /**
     * 设置背景纯色
     * @param color 已经转换好的颜色值
     */
    fun setBgSingleColor(color: Int) {
        for (columnIndex in 0 until mBgColorArray.size) {
            for (rowIndex in 0 until mBgColorArray[columnIndex].size) {
                mBgColorArray[columnIndex][rowIndex] = color
            }
        }
        mBoxesColor = color
        mLinearGradientColorArray = null
        mOrientation = -1
        invalidate()
    }

    /**
     * 设置背景线性颜色
     * @param colors 方向颜色
     * @param orientation 这里代表颜色方向
     */
    fun setBgLinearGradientColors(
        colors: IntArray,
        @LinearLayoutCompat.OrientationMode orientation: Int = LinearLayoutCompat.VERTICAL,
    ) {
        try {
            val bitmap = MyTextUtils.getBgBitmap(
                colors = MyTextUtils.getColorFromRes(colors),
                orientation = orientation,
                width = mBoxRowCount
            )
            val color2DArray = MyTextUtils.getColorArray(bitmap)
            for (columnIndex in 0 until mBgColorArray.size) {
                for (rowIndex in 0 until mBgColorArray[columnIndex].size) {
                    mBgColorArray[columnIndex][rowIndex] = color2DArray[columnIndex][rowIndex]
                }
            }
            mLinearGradientColorArray = colors
            mOrientation = orientation
            invalidate()
        } catch (e: Exception) {
            print(e)
        }
    }

    /**
     * 移除最后一个字符
     */
    @SuppressLint("WrongConstant")
    fun deleteLastCharacter() {
        if (mCharBitmapWithList.isNotEmpty()) {
            //重新绘制背景
            val totalCharWith = getTotalCharWith()
            val with = mCharBitmapWithList.removeLast()
            val temporaryBoxRowCount = max(totalCharWith-with, mMinBoxRowCount)
            if (totalCharWith > mMinBoxRowCount) {
                if (mOrientation != -1) {
                    //线性颜色像素点
                    val bgBitmap = MyTextUtils.getBgBitmap(
                        colors = mLinearGradientColorArray!!,
                        orientation = mOrientation,
                        width = temporaryBoxRowCount
                    )
                    mBgColorArray = MyTextUtils.getColorArray(bgBitmap)
                    mBoxRowCount = max(temporaryBoxRowCount, mMinBoxRowCount)
                } else {
                    //纯色背景像素点
                    for (columnIndex in 0 until mBgColorArray.size) {
                        for (rowIndex in 0 until mBoxRowCount - temporaryBoxRowCount) {
                            mBgColorArray[columnIndex].removeLast()
                        }
                    }
                    mBoxRowCount = max(totalCharWith-with, mMinBoxRowCount)
                }
            }
            for (columnIndex in 0 until mTextColorArray.size) {
                for (rowIndex in 0 until with) {
                    mTextColorArray[columnIndex].removeLast()
                }
            }
            if(calculateHorizontalWith()-with>0){
                if(mScroller.finalX>calculateHorizontalWith()-width){
                    mScroller.startScroll(mScroller.finalX,mScroller.finalY,-(mScroller.finalX-(calculateHorizontalWith() - width) - paddingStart - paddingEnd),0,200)
                }
            }else{
                mScroller.startScroll(mScroller.finalX,mScroller.finalY,-mScroller.finalX,0,200)
            }
            Log.i("addNewCharacter", "纵向="+mBgColorArray.size+",横向="+mBgColorArray[0].size+",mBoxRowCount="+mBoxRowCount+",mBoxColumnCount="+mBoxColumnCount)
            //这里不用invalidate,可能因为涉及多线程,有一定概率导致滑动失效
            postInvalidate()
        }
    }

    /**
     * 添加字符
     */
    @SuppressLint("WrongConstant")
    fun addNewCharacter(char: CharSequence) {
        if(mTurnMode == RIGHT_MODE ){
            rightMode()
        }else if(mTurnMode == LEFT_MODE){
            leftMode()
        }
        val charBitmaps = mutableListOf<Bitmap>()
        val charColorArray = mutableListOf<MutableList<MutableList<Int>>>()
        var addTotalWith = 0
        for (element in char) {
            val charBitmap = MyTextUtils.getBitmapFromText(element)

            mCharBitmapWithList.add(charBitmap.width)
            addTotalWith += charBitmap.width

            charBitmaps.add(charBitmap)
            charColorArray.add(MyTextUtils.getColorArray(charBitmap))
        }
        for (index in 0 until charColorArray.size) {
            val charColor = charColorArray[index]
            for (columnIndex in 0 until mBoxColumnCount) {
                if (columnIndex > mTextColorArray.size - 1) {
                    mTextColorArray.add(mutableListOf())
                }
                for (rowIndex in 0 until charColor[columnIndex].size) {
                    mTextColorArray[columnIndex].add(charColor[columnIndex][rowIndex])
                }
            }
        }
        if (getTotalCharWith() > mMinBoxRowCount) {
            if (mOrientation != -1) {
                //线性颜色像素点
                val bgBitmap = MyTextUtils.getBgBitmap(
                    colors = mLinearGradientColorArray!!,
                    orientation = mOrientation,
                    width = getTotalCharWith()
                )
                mBgColorArray = MyTextUtils.getColorArray(bgBitmap)
            } else {
                //纯色背景像素点
                for (columnIndex in 0 until mBoxColumnCount) {
                    for (rowIndex in 0 until (getTotalCharWith() - mBoxRowCount)) {
                        mBgColorArray[columnIndex].add(mBoxesColor)
                    }
                }
            }
        }
        mBoxRowCount = max(getTotalCharWith(), mMinBoxRowCount)
        if(calculateHorizontalWith()>width){
            Log.i("HorizontalWith", "总长度="+calculateHorizontalWith()+",滑动距离="+(calculateHorizontalWith()-mScroller.finalX - width)+",mScroller.finalX="+mScroller.finalX+",width="+width)
            if(mTurnMode != RIGHT_MODE && mTurnMode != LEFT_MODE){
                mScroller.startScroll(mScroller.finalX,mScroller.finalY,calculateHorizontalWith()-mScroller.finalX - width + paddingStart + paddingEnd,0,200)
            }
        }
        Log.i("addNewCharacter", "横向="+mBgColorArray.size+",纵向="+mBgColorArray[0].size+",mBoxRowCount="+mBoxRowCount+",mBoxColumnCount="+mBoxColumnCount)
        //这里不用invalidate,可能因为涉及多线程,有一定概率导致滑动失效
        postInvalidate()
    }



    /**
     * 添加字符
     */
    @SuppressLint("WrongConstant")
    fun addSymbol(bitmap: Bitmap) {
        if(mTurnMode == RIGHT_MODE ){
            rightMode()
        }else if(mTurnMode == LEFT_MODE){
            leftMode()
        }
        val charBitmaps = mutableListOf<Bitmap>()
        charBitmaps.add(bitmap)
        val charColorArray = mutableListOf<MutableList<MutableList<Int>>>()
        charColorArray.add(MyTextUtils.getColorArray(bitmap))
        mCharBitmapWithList.add(bitmap.width)

        for (index in 0 until charColorArray.size) {
            val charColor = charColorArray[index]
            for (columnIndex in 0 until mBoxColumnCount) {
                if (columnIndex > mTextColorArray.size - 1) {
                    mTextColorArray.add(mutableListOf())
                }
                for (rowIndex in 0 until charColor[columnIndex].size) {
                    mTextColorArray[columnIndex].add(charColor[columnIndex][rowIndex])
                }
            }
        }
        if (getTotalCharWith() > mMinBoxRowCount) {
            if (mOrientation != -1) {
                //线性颜色像素点
                val bgBitmap = MyTextUtils.getBgBitmap(
                    colors = mLinearGradientColorArray!!,
                    orientation = mOrientation,
                    width = getTotalCharWith()
                )
                mBgColorArray = MyTextUtils.getColorArray(bgBitmap)
            } else {
                //纯色背景像素点
                for (columnIndex in 0 until mBoxColumnCount) {
                    for (rowIndex in 0 until (getTotalCharWith() - mBoxRowCount)) {
                        mBgColorArray[columnIndex].add(mBoxesColor)
                    }
                }
            }
        }
        mBoxRowCount = max(getTotalCharWith(), mMinBoxRowCount)
        if(calculateHorizontalWith()>width){
            Log.i("HorizontalWith", "总长度="+calculateHorizontalWith()+",滑动距离="+(calculateHorizontalWith()-mScroller.finalX - width)+",mScroller.finalX="+mScroller.finalX+",width="+width)
            if(mTurnMode != RIGHT_MODE && mTurnMode != LEFT_MODE){
                mScroller.startScroll(mScroller.finalX,mScroller.finalY,calculateHorizontalWith()-mScroller.finalX - width + paddingStart + paddingEnd,0,200)
            }
        }
        Log.i("addNewCharacter", "横向="+mBgColorArray.size+",纵向="+mBgColorArray[0].size+",mBoxRowCount="+mBoxRowCount+",mBoxColumnCount="+mBoxColumnCount)
        //这里不用invalidate,可能因为涉及多线程,有一定概率导致滑动失效
        postInvalidate()
    }


    /**
     * 获取所有字符串像素长度
     */
    private fun getTotalCharWith(): Int {
        var addTotalWith = 0
        for (index in 0 until mCharBitmapWithList.size) {
            addTotalWith += mCharBitmapWithList[index]
        }
        return addTotalWith
    }

    /**
     * 计算包括在布局以外的长度
     */
    private fun calculateHorizontalWith(): Int {
        val allTotalWith = mBoxRowCount*mBoxWith+mBoxGap*(mBoxRowCount-1)
        return allTotalWith.toInt()
    }

    /**
     * 获取滚动完毕的距离
     */
    private fun rollingDistance(): Int {
        return calculateHorizontalWith()+width-paddingStart-paddingEnd
    }

    /**
     * 假如是常态模式或者闪光模式才启用滑动
     */
    private fun isEnableSlide():Boolean{
        return mTurnMode == NORMALIZATION_MODE || mTurnMode == FLASH_MODE
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        mViewHandler!!.removeMessages(LEFT_MODE)
        mViewHandler!!.removeMessages(RIGHT_MODE)
        mViewHandler!!.removeMessages(FLASH_MODE)
        if(mViewHandler!=null){
            mViewHandler = null
        }
    }

    fun flashMode(){
        if(mTurnMode == FLASH_MODE){
            return
        }
        mTurnMode = FLASH_MODE
        reflectMethod(DecelerateInterpolator())
        mViewHandler!!.removeMessages(LEFT_MODE)
        mViewHandler!!.removeMessages(RIGHT_MODE)
        mViewHandler!!.sendEmptyMessage(FLASH_MODE)
    }

    fun leftMode() {
        reflectMethod(LinearInterpolator())
        mViewHandler!!.removeMessages(RIGHT_MODE)
        mViewHandler!!.removeMessages(FLASH_MODE)
        mViewHandler!!.removeMessages(LEFT_MODE)
        mViewHandler!!.sendEmptyMessage(LEFT_MODE)
    }

    fun rightMode() {
        reflectMethod(LinearInterpolator())
        mViewHandler!!.removeMessages(LEFT_MODE)
        mViewHandler!!.removeMessages(FLASH_MODE)
        mViewHandler!!.removeMessages(RIGHT_MODE)
        mViewHandler!!.sendEmptyMessage(RIGHT_MODE)
    }

    fun normalizationMode(){
        mTurnMode = NORMALIZATION_MODE
        mIsFlashing = false
        mViewHandler!!.removeMessages(LEFT_MODE)
        mViewHandler!!.removeMessages(RIGHT_MODE)
        mViewHandler!!.removeMessages(FLASH_MODE)
        reflectMethod(DecelerateInterpolator())
        mScroller.forceFinished(true)
        mScroller.startScroll(mScroller.finalX,0,-mScroller.finalX,0)
    }

    /**
     * 设置滚动速度
     */
    fun setScrollSpeed(speed:Int){
        mSpeed = speed
    }

    /**
     * 设置滚动速度
     */
    fun getScrollSpeed():Int {
        val scale: Float = context.resources.displayMetrics.density
        return (mSpeed * scale + 0.5f).toInt()
    }

    inner class ViewHandler(looper: Looper) : Handler(looper){

        override fun handleMessage(msg: Message) {
            when(msg.what){

                LEFT_MODE->{
                    mScroller.forceFinished(true)
                    mIsFlashing = false
                    mTurnMode = LEFT_MODE
                    //滑动时间 = 滑动一圈的距离/滑动速度
                    val duration = rollingDistance()/getScrollSpeed()*500
                    mScroller.startScroll(-width,0,rollingDistance(),0,duration)
                    postInvalidate()
                    sendEmptyMessageDelayed(LEFT_MODE, duration.toLong())
                }
                FLASH_MODE->{
                    mScroller.forceFinished(true)
                    mIsFlashing = !mIsFlashing
                    postInvalidate()
                    sendEmptyMessageDelayed(FLASH_MODE,300)
                }
                RIGHT_MODE->{
                    mScroller.forceFinished(true)
                    mIsFlashing = false
                    mTurnMode = RIGHT_MODE
                    //滑动时间 = 滑动一圈的距离/滑动速度
                    val duration = rollingDistance()/getScrollSpeed()*500
                    mScroller.startScroll(calculateHorizontalWith(),0,-rollingDistance(),0,duration)
                    postInvalidate()
                    sendEmptyMessageDelayed(RIGHT_MODE, duration.toLong())
                }

            }
        }
    }

    /**
     * 反射修改插值器
     */
    private fun reflectMethod(interpolator: android.view.animation.Interpolator) {
        try {
            val fields: Array<Field> = Scroller::class.java.declaredFields
            for(element in fields){
                if("mInterpolator" == element.name) {
                    element.isAccessible = true
                    element.set(mScroller, interpolator)
                }
            }
        }catch (e:Exception){

        }
    }

    companion object{
        const val LEFT_MODE = 1
        const val RIGHT_MODE = 2
        const val FLASH_MODE = 3
        const val NORMALIZATION_MODE = -1
    }

}

